
# Network threadding
from network import networkThread

# Preferences and previous challenges windows
from preferences import dpcPreferences
import previousChallenges
from importChallenges import dpcImportDialog

# Database
from dpcDBs import settingsTable, validateDBs, userTable
from dpcDBs.log import log

# Code parsers
from parsers import validateLogin, parseChallengeEntries

# Interited from gtk.Table. Charting and score keeping
from dpcGUI import challengeSummary

# GTK helper functions
from gui.helperFuncs import imageButton_stock

# Timer
from gobject import timeout_add, source_remove

# GTK and gobject
import pygtk
pygtk.require( '2.0' )
import gtk

from time import gmtime, strftime

# Convenience current time for events
def now():
  return strftime( "%Y-%m-%d %H:%M:%S", gmtime() )


# The main window class. Effectively 'main'
class mainWindow( gtk.Window ):




  # INITIALISATION
  def __init__( self ):
    gtk.Window.__init__( self )
    gtk.threads_init()
    self.set_title( "DPC Challenge Monitor" )
    self.set_icon_from_file( "dpc.ico" )
    self.set_position( gtk.WIN_POS_CENTER_ALWAYS )
    self.connect( "destroy", self.kill )


    # Login status
    self.loggedIn = False
    self.previousChallenges = None



    # Network daemon. This class executes a URL request in a separate
    # thread. Then it signals a callback in the main thread
    self.network = networkThread();
    self.network.connect( networkThread.signalDoneName,
                          self.requestComplete )
    self.network.start()


    # Current preferences
    self.preferences = settingsTable.getSettings();
    self.user = None
    self.timeout = None


    # Challenges summary container
    self.notebook = gtk.Notebook()




    # A table to hold all the widgets
    table = gtk.Table()
    table.resize( 2, 2 )

    # The top row of buttons (refresh/prefs/etc)
    table.attach( self.genIconRow(),
                  0, 1, 0, 1,
                  gtk.FILL | gtk.EXPAND,
                  gtk.FILL,
                  10, 10 )

    # A notebook which holds all the challenge summaries
    # in separate tabs
    table.attach( self.notebook,
                  0, 1, 1, 2,
                  gtk.EXPAND | gtk.FILL,
                  gtk.EXPAND | gtk.FILL,
                  10, 10 )




    # Add the table to the window 
    self.add( table )

    # Set sizes of the widgets and show
    table.set_size_request( 450, 550 )
    self.set_size_request( 550, 650 )
    self.show_all()




    # Open up the preferences if the username or password aren't set
    if self.canLogIn() == False:
      self.openPreferences()
    else:
      # If the settings are there, simulate a click
      if self.preferences.update_auto:
        self.refreshButton.clicked()

    self.timeoutStart()



  # A quick check to see whether or not it is possible to log in
  # with the current preferences
  def canLogIn( self ):
    u = self.preferences.login_username
    p = self.preferences.login_password

    return len( u ) > 0 and len( p ) > 0



  # This function handles the timeout 
  def timeoutStart( self ):
    if self.preferences.update_auto == False:
      return

    # Set up the timeout (convert to minutes)
    interval = self.preferences.update_period * 60 * 1000
    if interval <= 0:
      interval = 1 * 60 * 1000

    #self.timeout = timeout_add( 500, self.doRefresh, True )
    self.timeout = timeout_add( interval, self.doRefresh, True )

  # Stop the refresh function
  def timeoutStop( self ):
    if self.timeout is not None:
      source_remove( self.timeout )
      self.timeout = None


  # Destroy method
  def kill( self, button = None ):
    self.timeoutStop()
    gtk.main_quit()



  # Generates the row of columns on top of the window
  def genIconRow( self ):
    # Common properties
    expand = True
    fill = True
    padding = 1
    size = gtk.ICON_SIZE_SMALL_TOOLBAR

    box = gtk.HBox( False, 2 );




    # Open home page
    def homepageClicked( button ):
      import webbrowser
      webbrowser.open( 'http://www.dpchallenge.com/index.php' )

    b = imageButton_stock( text = "Go to dpchallenge.com",
                           stockID = gtk.STOCK_HOME,
                           size = size )
    b.connect( 'clicked', homepageClicked )
    box.pack_start( b, expand, fill, padding )



    # Import other challenges
    b = imageButton_stock( text = "Import challenges",
                           stockID = gtk.STOCK_ADD,
                           size = size )
    b.connect( 'clicked', self.importChallenges )
    box.pack_start( b, expand, fill, padding )



    # Open previous challenges
    b = imageButton_stock( text = "Open Challenges",
                           stockID = gtk.STOCK_OPEN,
                           size = size )
    b.connect( 'clicked', self.openChallenges )
    box.pack_start( b, expand, fill, padding )



    # Program preferences
    b = imageButton_stock( text = "Open Preferences",
                           stockID = gtk.STOCK_PREFERENCES,
                           size = size )
    b.connect( 'clicked', self.openPreferences )
    box.pack_start( b, expand, fill, padding )


    # Refresh
    b = imageButton_stock( text = "Refresh scores",
                           label = "Refresh scores",
                           stockID = gtk.STOCK_REFRESH,
                           size = size )
    b.connect( 'clicked', self.doRefresh )
    box.pack_start( b, expand, fill, padding )
    self.refreshButton = b


    box.show()
    return box



  # This is called back whenever the preferences are changed
  # from the preferences window. It ensures the current prefs
  # are the most up to date
  def settingsChanged( self, preferences ):
    self.preferences = preferences

    # Restart the timeout if the preferences have changed
    self.timeoutStop()
    self.timeoutStart()

  # Open the preference window with a reference to the prefs
  # callback
  def openPreferences( self, button = None ):
    log.i( self, 'Opening preferences' )
    dpcPreferences( self.settingsChanged )



  # Opens up an import dialog to include old score monitorings
  # in the new DB
  def importChallenges( self, button = None ):
    log.i( self, 'Importing new challenges' )
    dpcImportDialog()



  # A function called when the open button is clicked. Previous
  # entries monitored by the challenge monitor are available 
  # for reviewing
  def openChallenges( self, button ):
    log.i( self, 'Opening previous challenges' )
    previousChallenges.previousChallenges()



  # Called whenever 'refresh' is clicked. Automatically handles
  # login and score update depending on login status. 
  def doRefresh( self, button = None, fromTimeout = False ):
    if self.refreshButton.get_sensitive() == False:
      return True

    self.refreshButton.set_sensitive( False )

    # Only continue if this function is called from the timeout and
    # if automatic refreshing has been selected from the preferences
    if fromTimeout == True and self.preferences.update_auto == False:
      return True

    log.i( self, 'doRefresh called' )
    print now()


    if self.canLogIn() == True:
      if self.loggedIn == False:
        # If loggedIn is False, must first log in
        print 'Logging in...'
        log.i( self, 'Pushing login' )
        url = 'https://www.dpchallenge.com/login.php'
        params = { 'USERNAME'      : self.preferences.login_username,
                   'PASSWORD'      : self.preferences.login_password,
                   'SAVE_PASSWORD' : '1',
                   'SAVE_USERNAME' : '1' }
        self.network.addRequest( url, params )


      else:
        # If already have logged in, update the challenge stats
        print 'Updating challenge stats'
        log.i( self, 'Pushing refresh ' )
        url = 'http://www.dpchallenge.com/challenge_stats.php?action=update'
        params = {}
        self.network.addRequest( url, params )


    else:
      log.i( self, 'Cannot log in--preferences not set' )

    return True




  # This function is signalled whenever self.network has finished 
  # its requesting
  def requestComplete( self, sender, url, params, resp ):
    # Keep a track of the old and new login status so as to decide 
    # whether to login or update
    oldLoginStatus = self.loggedIn;
    self.loggedIn = validateLogin( resp )
    log.i( self, 'Request complete (from ' + url + ')' )


    # If the login was successful, now refresh the scores 
    if self.loggedIn == True:
      # If logged in previously, update has been done, so parse 
      # the source
      if oldLoginStatus == True:
        log.i( self, 'Parsing source' )
        self.parseChallenges( url, params, resp )


      else:
        # Just logged in. No scores update done yet, so need to 
        # do a new refresh
        log.i( self, 'Login successful' )
        username = resp.cookies["USERNAME"].lower()
        self.user = userTable.selectBy( username = username )
        if self.user.count() == 0:
          self.user = userTable( username = username )
        else:
          self.user = self.user[0]
        self.doRefresh()
    else:
      log.i( self, 'Login not successful' )
    self.refreshButton.set_sensitive( True )





  # Are logged in. Parse challenge entries and update self.notebook
  # with the challenge tabs
  def parseChallenges( self, url, param, resp ):
    # Clear the notebook 
    log.i( self, 'Removing notebook pages' )
    while self.notebook.get_n_pages():
      self.notebook.remove_page( 0 )

    return

    # Parse the challenge info
    log.i( self, 'Parsing challenge details' )
    challengeIDs, entryNames, challengeNames, newScore = \
      parseChallengeEntries( self.user, resp )


    # Add the images to the notebook
    log.i( self, 'Adding challenges' )
    for i, challengeID in enumerate( challengeIDs ):
      ch = challengeSummary( self.user, challengeID )
      ch.show()

      tabLabel = str( entryNames[i] )

      # Add the new one and 
      self.notebook.insert_page( ch, gtk.Label( tabLabel ) )

    log.i( self, 'Done' )
    self.notebook.show()
    self.show_all()



def main():
  validateDBs()
  win = mainWindow()
  gtk.main()

if __name__ == '__main__':
  main()
